﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using S9Engine;
using System.Data.Objects;
using System.Linq.Expressions;
using System.Text;
using System.IO;


namespace S9Engine
{
    public class Parser: System.Web.UI.Page
    {
        #region Declare Variables

        public S9Engine _parser;
        public DinorichEntities _DR;
        public string _currentLanguage;
        public int _rowsPerPage;
        public int _pageRange;
        public string _webcmsPath;

        public Func<long, int, List<ListCategory>> BuildListCategory;
        public Func<long, int, List<SelectCategory>> BuildSelectCategory;

        #endregion Declare Variables

        public Parser()
        {
            _parser = new S9Engine();
            _DR = new DinorichEntities();
        }

        #region Init Functions

        public void LoadFile(string filePath, bool ajax)
        {
            _parser.LoadFile(filePath);
            if (!ajax) AssignCommon();
        }

        public void WriteError(Exception ex)
        {
            _parser.Assign("errorCode", "Error:" + ex.ToString() ?? ex.Message);
        }

        public void InitAll()
        {
            _currentLanguage = Session["Language"] == null ? _parser.GetConfig("DefaultLanguage", "VN") : Session["Language"].ToString();
            _rowsPerPage = int.Parse(_parser.GetConfig("RowsPerPage", "8"));
            _pageRange = int.Parse(_parser.GetConfig("PageRange", "9"));
            _webcmsPath = _parser.GetConfig("webcmsPath", "~/../webcms");

            _parser.Assign("currentLanguage", _currentLanguage);
            _parser.Assign("webcmsPath", _webcmsPath);
        }

        private void AssignCommon()
        {
            try
            {
                _parser.Assign("fullName", (Session["FullName"] as string) ?? "Khách");

                LoadLanguage();
            }
            catch (Exception ex)
            {
                WriteError(ex);
            }
        }

        protected override void Render(System.Web.UI.HtmlTextWriter writer)
        {
            writer.Write(_parser._outContent);
        }

        #endregion Init Functions

        #region Other Functions

        public void LoadLanguage()
        {
            try
            {
                List<Languages> languages = _DR.Languages.ToList();

                foreach (Languages l in languages)
                {
                    _parser.Assign("langCode", l.Code);
                    _parser.Assign("langName", l.Name);
                    _parser.Parse("Main.Language.LanguageItem");
                    _parser.Parse("Main.LanguageFlag.LanguageFlagItem");
                }

                if (languages.Count > 0)
                {
                    _parser.Parse("Main.LanguageFlag");
                    _parser.Parse("Main.Language");
                }
            }
            catch (Exception ex)
            {
                WriteError(ex);
            }
        }

        public bool CheckLogin()
        {
            return (Session["IsLogged"] != null) && (Session["IsLogged"] as string == "1");
        }

        public bool IsNullValues(params object[] values)
        {
            foreach (object o in values)
            {
                if (o == null) return true;
            }

            return false;
        }

        #endregion Other Functions

        #region Product Functions

        public long AddNewProduct(string productDate, string productExcerpt, string productName, string productPrice, string productQuantity, string productImage, string productContent, bool saveChange, string productManufactory)
        {
            Products product = new Products();

            product.Date = Convert.ToDateTime(Convert.ToDateTime(productDate).ToShortDateString());
            product.Description = productExcerpt;
            product.Name = productName;
            product.Price = double.Parse(productPrice);
            product.Quantity = int.Parse(productQuantity);
            product.Status = string.Empty;
            product.LanguageCode = _currentLanguage;
            product.Image = productImage;
            product.Content = productContent;
            product.Manufactory = productManufactory;
            product.LanguageCode = _currentLanguage;

            _DR.AddToProducts(product);

            if (saveChange)
            {
                _DR.SaveChanges();
                return product.ID;
            }

            product = null;

            return 0;
        }

        public bool EditProduct(long productID, string productDate, string productExcerpt, string productName, string productPrice, string productQuantity, string productImage, string productContent, bool saveChange, string productManufactory)
        {
            Products product = _DR.Products.Where(p => p.ID.Equals(productID)).FirstOrDefault();

            if (product == null) return false;

            product.Date = Convert.ToDateTime(Convert.ToDateTime(productDate).ToShortDateString());
            product.Description = productExcerpt;
            product.Name = productName;
            product.Price = double.Parse(productPrice);
            product.Quantity = int.Parse(productQuantity);
            product.Image = productImage;
            product.Content = productContent;
            product.Manufactory = productManufactory;

            if (saveChange) _DR.SaveChanges();

            return true;
        }

        public bool DeleteProduct(long productID, bool saveChange)
        {
            Products product = _DR.Products.Where(p => p.ID.Equals(productID)).FirstOrDefault();

            if (product == null) return false;

            _DR.DeleteObject(product);

            if (saveChange) _DR.SaveChanges();

            product = null;

            return true;
        }

        public bool DeleteProduct(long[] productIDs, bool saveChange)
        {
            List<Products> products = _DR.Products.WhereIn(p => p.ID, productIDs).ToList();

            foreach (Products product in products)
            {
                _DR.DeleteObject(product);
            }

            if (saveChange) _DR.SaveChanges();

            products = null;

            return products.Count > 0;
        }

        #endregion Product Functions

        #region Meta Functions

        public long AddNewMeta(long objectID, string type, string key, string value, bool saveChange)
        {
            Meta meta = new Meta();

            meta.Object = objectID;
            meta.Type = type;
            meta.Key = key;
            meta.Value = value;
            meta.LanguageCode = _currentLanguage;

            _DR.AddToMeta(meta);

            if (saveChange)
            {
                _DR.SaveChanges();
                return meta.ID;
            }

            meta = null;

            return 0;
        }

        public bool EditMeta(long metaID, string value, bool saveChange)
        {
            Meta meta = _DR.Meta.Where(m => m.ID.Equals(metaID)).FirstOrDefault();

            if (meta == null) return false;

            meta.Value = value;

            if (saveChange) _DR.SaveChanges();

            return true;
        }

        public bool EditMetaByObject(long objectID, string type, string key, string value, bool saveChange)
        {
            Meta meta = _DR.Meta.Where(m => m.Object.Equals(objectID) && m.Type.Equals(type) && m.Key.Equals(key)).FirstOrDefault();

            if (meta == null) return false;

            meta.Value = value;

            if (saveChange)
            {
                _DR.SaveChanges();
                meta = null;
            }

            return true;
        }

        public bool DeleteMeta(long metaID, bool saveChange)
        {
            Meta meta = _DR.Meta.Where(m => m.ID.Equals(metaID)).FirstOrDefault();

            if (meta == null) return false;

            _DR.DeleteObject(meta);

            if (saveChange) _DR.SaveChanges();

            meta = null;

            return true;
        }

        public bool DeleteMetas(long[] metaIDs, bool saveChange)
        {
            List<Meta> metas = _DR.Meta.WhereIn(m => m.ID, metaIDs).ToList();

            foreach (Meta meta in metas)
            {
                _DR.DeleteObject(meta);
            }

            if (saveChange) _DR.SaveChanges();

            metas = null;

            return metas.Count > 0;
        }

        #endregion Meta Functions

        #region Relation Function

        public long AddNewRelation(string type, long child, long parent, long order, bool saveChange)
        {
            Relations relation = new Relations();

            relation.Type = type;
            relation.Child = child;
            relation.Parent = parent;
            relation.Order = order;
            relation.LanguageCode = _currentLanguage;

            _DR.AddToRelations(relation);

            if (saveChange)
            {
                _DR.SaveChanges();
                return relation.ID;
            }

            relation = null;

            return 0;
        }

        public bool DeleteRelationByChild(long child, string type)
        {
            List<Relations> relations = _DR.Relations.Where(r => r.Type.Equals("product-category") && r.Child.Equals(child)).ToList();

            foreach (Relations r in relations)
            {
                _DR.DeleteObject(r);
            }

            return relations.Count > 0;

            relations = null;
        }

        #endregion Relation Function
        #region RoomGallery
        public long AddNewRoomGallery(string GroupName, string Name, string Image, bool SaveChange) {
            Rooms room = new Rooms();
            room.GroupName = GroupName;
            room.Name = Name;
            room.Image = Image;
            room.LanguageCode = _currentLanguage;

            _DR.AddToRooms(room);
            if (SaveChange) { _DR.SaveChanges(); return room.ID; }
            room = null;
            return 0;
        }
        public bool EditRoom(long roomID, string roomGroupName, string roomName, string roomImage, bool saveChange)
        {            
            Rooms room = _DR.Rooms.Where(r=>r.ID.Equals(roomID)).FirstOrDefault();
            if (room == null) return false;
            room.GroupName = roomGroupName;
            room.Name = roomName;
            room.Image = roomImage;

            if (saveChange) _DR.SaveChanges();

            return true;
        }
        public bool DeleteRoom(long[] roomIDs, bool saveChange)
        {            
            List<Rooms> rooms = _DR.Rooms.WhereIn(r=>r.ID, roomIDs).ToList();
            foreach (Rooms room in rooms)
            {
                _DR.DeleteObject(room);
            }

            if (saveChange) _DR.SaveChanges();

            rooms = null;

            return rooms.Count > 0;
        }
        #endregion RoomGallery

        #region RoomDetails
        public long AddNewRoomDetails(long objectID, string type, string coordinates, string value, string content, string link, bool saveChange)
        {
            RoomDetails roomDetail = new RoomDetails();

            roomDetail.Object = objectID;
            roomDetail.Type = type;
            roomDetail.Coordinates = coordinates;
            roomDetail.Value = value;
            roomDetail.Content = content;
            roomDetail.Link = link;
            roomDetail.LanguageCode = _currentLanguage;

            _DR.AddToRoomDetails(roomDetail);

            if (saveChange)
            {
                _DR.SaveChanges();
                return roomDetail.ID;
            }

            roomDetail = null;

            return 0;
        }

        public bool UpdateRoomDetails(long id, long objects, string type, string coordinate, string value, string content, string link, bool saveChange) {
            RoomDetails roomDetails = _DR.RoomDetails.Where(r => r.ID.Equals(id)).FirstOrDefault();
            if (roomDetails == null) return false;
            
            roomDetails.Object=objects;
            roomDetails.Type=type;
            roomDetails.Coordinates=coordinate;
            roomDetails.Value=value;
            roomDetails.Content=content;
            roomDetails.Link=link;

            if (saveChange) _DR.SaveChanges();

            return true;
        }

        public bool DeleteRoomDetails(long[] roomDetailsIDs, bool saveChange)
        {
            List<RoomDetails> roomDetails = _DR.RoomDetails.WhereIn(r => r.ID, roomDetailsIDs).ToList();
            foreach (RoomDetails room in roomDetails)
            {
                _DR.DeleteObject(room);
            }

            if (saveChange) _DR.SaveChanges();

            roomDetails = null;

            return roomDetails.Count > 0;
        }

        public IEnumerable<GalleryList> LoadAllGallery()
        {
            var query = (from g in _DR.Rooms.Where(g1 => g1.LanguageCode.Equals(_currentLanguage))
                         join d in _DR.RoomDetails.Where(m => m.LanguageCode.Equals(_currentLanguage)).Select(m => new GalleryDetails() { ID = m.ID, Object = m.Object, Type = m.Type, Coordinate = m.Coordinates, Value = m.Value, Content = m.Content, Link = m.Link }) on g.ID equals d.Object into details
                         select new GalleryList()
                         {
                             ID = g.ID,
                             GroupName = g.GroupName,
                             Name = g.Name,
                             Image = g.Image,
                             Details = details
                         });
            IEnumerable<GalleryList> ret = query.ToList().DistinctBy(q => q.ID);

            return ret;
        }
        public void GalleryRoom()
        {
            //var list = LoadAllGallery().ToList();
            StringBuilder sb = new StringBuilder();
            sb.Append("var imagesCollection = {\"image\": [");
            int i = 0;
            //foreach (var g in list)
            //{
                //i++;
                string end = "}";
                sb.Append("{");
                sb.Append("\"id\": " + 0);
                sb.Append(", \"group\": \"" + "vietnam_map\"");
                sb.Append(", \"name\": \"" +"vietnam_map\"");
                sb.Append(", \"src\": \"" + _webcmsPath + "/uploads/image/vietnam.png\",");
                //List<GalleryDetails> dtSpot = g.Details.Where(d => d.Type.Equals("spot") && d.Object.Equals(g.ID)).ToList();
                //List<GalleryDetails> dtArea = g.Details.Where(d => d.Type.Equals("area") && d.Object.Equals(g.ID)).ToList();
                //List<GalleryDetails> dtTooltip = g.Details.Where(d => d.Type.Equals("tooltip") && d.Object.Equals(g.ID)).ToList();
                //List<GalleryDetails> dtInfo = g.Details.Where(d => d.Type.Equals("info") && d.Object.Equals(g.ID)).ToList();
                var dtSpot = (from r in _DR.RoomDetails.Where(r1 => r1.LanguageCode.Equals(_currentLanguage) && r1.Object.Equals(0))
                              select new
                              {
                                  ID=r.ID,
                                  Link=r.Link,
                                  Content=r.Content,
                                  Coordinate=r.Coordinates
                              }).DistinctBy(r1=>r1.ID).ToList();
                if (dtSpot.Count > 0)
                {
                    sb.Append("\"spot\": [");
                    for (int j = 0; j < dtSpot.Count; ++j)
                    {
                        string endDigit = (j == dtSpot.Count - 1) ? "" : ",";
                        sb.Append("{to: \"" + dtSpot[j].Link + "\"," + dtSpot[j].Coordinate + ", info: \"" + dtSpot[j].Content + "\"}" + endDigit);
                    }
                    sb.Append("],");
                }
                
                //if (dtArea.Count > 0)
                //{
                //    sb.Append("\"area\": [");
                //    for (int j = 0; j < dtArea.Count; ++j)
                //    {
                //        string endDigit = (j == dtArea.Count - 1) ? "" : ",";
                //        sb.Append("{" + dtArea[j].Coordinate + ", content: \"" + dtArea[j].Content + "\"}" + endDigit);
                //    }
                //    sb.Append("],");
                //}
                //if (dtTooltip.Count > 0)
                //{
                //    sb.Append("\"tooltip\": [");
                //    for (int j = 0; j < dtTooltip.Count; ++j)
                //    {
                //        string endDigit = (j == dtTooltip.Count - 1) ? "" : ",";
                //        sb.Append("{" + dtTooltip[j].Coordinate + ", content: \"" + dtTooltip[j].Content + "\"}" + endDigit);
                //    }
                //    sb.Append("],");
                //}
                //if (dtInfo.Count > 0)
                //{
                //    sb.Append("\"info\": [");
                //    for (int j = 0; j < dtInfo.Count; ++j)
                //    {
                //        string endDigit = (j == dtInfo.Count - 1) ? "" : ",";
                //        sb.Append("{id: " + dtInfo[j].ID + ", " + dtInfo[j].Coordinate + ", title: \"" + dtInfo[j].Value + "\", content:\"" + dtInfo[j].Content + "\", url: \"" + dtInfo[j].Link + "\"}" + endDigit);
                //    }
                //    sb.Append("]");
                //}
                sb.Append("\"info\": [");
                sb.Append("]");
                sb.Append(end);
            //}
            sb.Append("]};");
            string str = sb.ToString();
            File.WriteAllText(Server.MapPath("js/roomgallery.js"), str);
            
        }
        #endregion RoomDetails
        public string Fiter(string input)
        {
            string tmp = input;
            string[] tmpFilter = { "x:", "y:", "width:", "height:", "x1:", "y1:", "x2:", "y2:" };
            for (int j = 0; j < tmpFilter.Length; ++j)
            {
                tmp = tmp.Replace(tmpFilter[j], "");
            }
            return tmp.Trim();
        }
    }

    #region Other Classes

    public static class LINQTool
    {
        public static string Select<T, TProperty>(this IEnumerable<T> obj, Func<T, TProperty> keyProperty, Func<T, TProperty> valueProperty, string key) where T : class
        {
            var ret = obj.Where(o => keyProperty(o).Equals(key)).Select(o => valueProperty(o)).FirstOrDefault();
            return null == ret ? string.Empty : ret.ToString();
        }
    }

    public class GalleryDetails
    {
        public long ID { get; set; }
        public long Object { get; set; }
        public string Type { get; set; }
        public string Coordinate { get; set; }
        public string Value { get; set; }
        public string Content { get; set; }
        public string Link { get; set; }
        public string Language { get; set; }
    }

    public class GalleryList
    {
        public long ID { get; set; }
        public string GroupName { get; set; }
        public string Name { get; set; }
        public string Image { get; set; }
        public IEnumerable<GalleryDetails> Details { get; set; }
    }
    public class ListCategory
    {
        public long ID { get; set; }
        public string Name { get; set; }
        public long Parent { get; set; }
        public string Description { get; set; }
    }

    public class SelectCategory
    {
        public long ID { get; set; }
        public string Name { get; set; }
        public long Parent { get; set; }
    }

    public class ObjectPosition
    {
        public long Key { get; set; }
        public long Position { get; set; }
        public long Order { get; set; }
    }

    #endregion Other Classes
}